// Package models redis数据操作类
package models

import (
	"ginmin/configs/drivers"
	m "ginmin/middleware"
	"github.com/gomodule/redigo/redis"
	"log"
)

var redisDb = drivers.RedisDb
var c PSubscriber

type Redis struct{}

type PSubscribeCallback func(pattern, channel, message string)

type PSubscriber struct {
	client redis.PubSubConn
	cbMap  map[string]PSubscribeCallback
}

//到期hook
/*func (service *ServerService) RedisHook(){
    redis := models.Redis{}
    redis.Psubscribe("__keyevent@1__:expired",PubCallback)
}

// PubCallback
// @Description: redis反射回调
// @param patter
// @param chann
// @param msg
func PubCallback(patter, chann, msg string) {
	log.Println("PubCallback patter : "+patter+" channel : ", chann, " message : ", msg)
}
*/

// Psubscribe
// @Description: redis订阅
// @receiver model
// @param channel
// @param cb
func (model *Redis) Psubscribe(channel interface{}, cb PSubscribeCallback) {
	c.client = redis.PubSubConn{redisDb.Get()}
	c.cbMap = make(map[string]PSubscribeCallback)
	go func() {
		for {
			switch res := c.client.Receive().(type) {
			case redis.Message:
				pattern := &res.Pattern
				channel := &res.Channel
				message := &res.Data
				c.cbMap[*channel](*pattern, *channel, string(*message))
			case redis.Subscription:
				log.Printf("%s: %s %d\n", res.Channel, res.Kind, res.Count)
			case error:
				log.Printf("error handle...")
				break
			}
		}
	}()
	err := c.client.PSubscribe(channel)
	if err != nil {
		log.Printf("redis Subscribe error.")
	}
	c.cbMap[channel.(string)] = cb
}

// Set
// @Description: set 存储值
// @receiver model
// @param key 字段
// @param value 数值
// @param ttl 过期时间
// @return error
func (model *Redis) Set(key string, value interface{}, ttl int) error {
	rc := redisDb.Get()
	defer rc.Close()
	serialized := drivers.Serializer(value)
	if rc.Err() != nil {
		return rc.Err()
	}
	if ttl > 0 {
		_, err := rc.Do("SETEX", key, ttl, serialized)
		if err != nil {
			return err
		}
	} else {
		_, err := rc.Do("SET", key, serialized)
		if err != nil {
			return err
		}
	}
	return nil
}

// Get
// @Description: Get取值
// @receiver model
// @param key 字段
// @return interface{} 返回数据
// @return bool
func (model *Redis) Get(key string) (interface{}, bool) {
	rc := redisDb.Get()
	defer rc.Close()
	if rc.Err() != nil {
		return nil, false
	}

	v, err := redis.Bytes(rc.Do("GET", key))
	if err != nil || v == nil {
		return nil, false
	}

	finalValue := drivers.Deserializer(v)

	return finalValue, true

}

// GetAll
// @Description: Gets 模糊取值
// @receiver model
// @param prefix 前缀
// @return map[int]interface{} 返回数据
func (model *Redis) GetAll(prefix string) map[int]interface{} {
	rc := redisDb.Get()
	defer rc.Close()
	if rc.Err() != nil {
		return nil
	}
	v, err := redis.Strings(rc.Do("KEYS", prefix))
	if err != nil {
		return nil
	}
	var res = make(map[int]interface{})
	for key, value := range v {
		val, _ := model.Get(value)
		res[key] = val
	}
	// 解码所得值
	return res
}

// Gets
// @Description: Gets批量取值
// @receiver model
// @param keys 字段
// @param prefix 前缀
// @return map[string]interface{} 返回数据
// @return []string 未查找到的字段
func (model *Redis) Gets(keys []string, prefix string) (map[string]interface{}, []string) {
	rc := redisDb.Get()
	defer rc.Close()
	if rc.Err() != nil {
		return nil, keys
	}

	var queryKeys = make([]string, len(keys))
	for key, value := range keys {
		queryKeys[key] = prefix + value
	}

	v, err := redis.ByteSlices(rc.Do("MGET", redis.Args{}.AddFlat(queryKeys)...))
	if err != nil {
		return nil, keys
	}

	var res = make(map[string]interface{})
	var missed = make([]string, 0, len(keys))

	for key, value := range v {
		decoded := drivers.Deserializer(value)
		if err != nil || decoded == nil {
			missed = append(missed, keys[key])
		} else {
			res[keys[key]] = decoded
		}
	}
	// 解码所得值
	return res, missed
}

// Sets
// @Description: 批量设置值
// @receiver model
// @param values 要设置的数据，字段名：数据
// @param prefix 前缀
// @return error
func (model *Redis) Sets(values map[string]interface{}, prefix string) error {
	rc := redisDb.Get()
	defer rc.Close()
	if rc.Err() != nil {
		return rc.Err()
	}
	var setValues = make(map[string]interface{})

	// 编码待设置值
	for key, value := range values {
		serialized := drivers.Serializer(value)
		setValues[prefix+key] = serialized
	}
	_, err := rc.Do("MSET", redis.Args{}.AddFlat(setValues)...)
	if err != nil {
		return err
	}
	return nil

}

// Delete
// @Description: 批量删除给定字段
// @receiver model
// @param keys 字段名
// @param prefix 前缀
// @return error
func (model *Redis) Delete(keys []string, prefix string) error {
	rc := redisDb.Get()
	defer rc.Close()
	if rc.Err() != nil {
		return rc.Err()
	}
	// 处理前缀
	for i := 0; i < len(keys); i++ {
		keys[i] = prefix + keys[i]
	}
	_, err := rc.Do("DEL", redis.Args{}.AddFlat(keys)...)
	if err != nil {
		return err
	}
	return nil
}

// DeleteAll
// @Description: 批量删除所有数据
// @receiver model
// @return error
func (model *Redis) DeleteAll() error {
	rc := redisDb.Get()
	defer rc.Close()
	if rc.Err() != nil {
		return rc.Err()
	}

	_, err := rc.Do("FLUSHDB")

	return err
}

// GetExpire
// @Description: 获取过期时间
// @receiver model
// @param key 字段
// @return int 返回数据
func (model *Redis) GetExpire(key string) int {
	rc := redisDb.Get()
	defer rc.Close()
	if rc.Err() != nil {
		return 0
	}

	ttlResult, err := rc.Do("TTL", key)
	if err != nil {
		return 0
	}
	return m.ToInt(ttlResult)
}
